using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using BakalarskaPraca.Forms;
using BakalarskaPraca.Generation.Data;
using BakalarskaPraca.Generation.Tasks.Abstract;
using BakalarskaPraca.Interfaces;
using Microsoft.DirectX;

namespace BakalarskaPraca.Generation.Tasks
{
    public abstract class PlantDistributionGenerationBase : GenerationProcess
    {
        protected GenerationOverview Overview;
        protected PlantLibrary PlantLibrary;
        public string PlantLibrarySource;
        protected Random RandomGenerator;
        protected List<Plant> Plants;
        private static int _iter;
        protected abstract string Name { get; }

        protected IProgressReporter Reporter; 

        protected PlantDistributionGenerationBase(List<HumidityPolygon> polygons, ModelData modelData) : base(polygons, modelData)
        {
            this.RandomGenerator = new Random();
            this.PlantLibrarySource = "trees.xml";
        }

        public sealed override void Run(IProgressReporter reporter)
        {
            this.Reporter = reporter;
            this.Reporter.ReportProgressMessage("creating overview");
            this.Overview = new GenerationOverview(this.Polygons, this.ModelData);
            this.Overview.Run(reporter);
            //this.Overview.PreviewData().Save("ppp" + _iter++ + ".jpg");
            this.Reporter.ReportProgressMessage(this.Name);
            this.PlantLibrary = new PlantLibrary(this.PlantLibrarySource);
            this.Populate();
            this.SavePlants();
        }

        protected abstract void Populate();

        protected virtual Plant PlantSeed()
        {
            int x = this.RandomGenerator.Next(this.GetBounds().X);
            int y = this.RandomGenerator.Next(this.GetBounds().Y);
            return this.PlantSeed(x, y);
        }

        protected virtual Plant PlantSeed(int x, int y)
        {
            if (!this.IsFree(x, y))
            {
                return null;
            }
            List<PlantData> possiblePlants = this.PlantLibrary.GetSuitablePlants(this.GetHumidityValue(x, y));
            if (possiblePlants.Any())
            {
                PlantData plantData = possiblePlants[this.RandomGenerator.Next(possiblePlants.Count)];
                Plant plant = new Plant();
                plant.X = x;
                plant.Y = y;
                plant.PlantData = plantData;
                return plant;
            }
            return null;
        }

        
        protected bool InBounds(int x, int y)
        {
            return x > 0 && y > 0 && x < this.GetBounds().X && y < this.GetBounds().Y;
        }

        
        public Bitmap VisualizePlants()
        {
            Bitmap b = new Bitmap(this.GetVisualizationBackground());
            
            Graphics g = Graphics.FromImage(b);
            
            this.Plants.ForEach(plant=>
                                     {
                                         Brush brush = new SolidBrush(Color.FromArgb(plant.PlantData.MinHumidity, plant.PlantData.MaxHumidity, plant.Age));
                                         g.FillRectangle(brush, (float) ((int) (plant.X - 5)), (int) (plant.Y - 5), 10, 10);
                                     }
                );
            return b;
        }

        protected bool IsFree(int x, int y)
        {
            return !this.Plants.Any(
                plant =>
                    {
                        if (plant != null)
                        {
                            return Math.Pow(plant.X - x, 2) + Math.Pow(plant.Y - y, 2) <
                                   Math.Pow(plant.PlantData.OccupyRadius, 2);
                        }
                        return false;
                    });
        }

        protected void SavePlants()
        {
            this.Plants.ForEach(plant => plant.InsertPlantNode(this.GetPosition(plant), this.ModelData.ColladaDocument));
        }

        protected Vector3 GetPosition(Plant plant)
        {
            return this.Overview.PlantPoints[(int)plant.X][(int)plant.Y].Position;
        }

        protected Point GetBounds()
        {
            return new Point(this.Overview.PlantPoints.Count(), this.Overview.PlantPoints[0].Count());
        }

        protected int GetHumidityValue(int x, int y)
        {
            if (this.InBounds(x, y) && this.Overview.PlantPoints[x][y].Available)
            {
                return this.Overview.PlantPoints[x][y].Humidity;
            }
            return -1;
        }

        protected virtual Bitmap GetVisualizationBackground()
        {
            return this.Overview.PreviewData();
        }
    }
}